package com.smartmail.receiving.imap;

import java.util.Properties;

import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;

import android.content.Context;
import android.net.ConnectivityManager;
import android.util.Log;

import com.smartmail.accounts.MailAccount;
import com.smartmail.receiving.ReceivingRequestsHandler;
import com.sun.mail.imap.IMAPFolder;

/**
 * 
 * @author Tomek
 * 
 * This class represents IMAP listening task.
 * It's responsibility is to immediate response on new message
 * arrival to mailbox.
 *
 */
public class IMAPListenMailboxTask implements Runnable {

	
	/**
	 * Public constructor.
	 * 
	 * @param mailAccount - Mail Account object which identifies mailbox to be listening
	 * @param context - Application context
	 */
	public IMAPListenMailboxTask(MailAccount mailAccount,Context context){
		
		_mailAccount = mailAccount;
		_context = context;
	}
	
	/**
	 * Implementation of listening task.
	 */
	@Override
	public void run() {
		
		Log.d(_logTag, "IMAPListenMailboxTask : start " + _mailAccount.getMailAddress());
		
		//check if thread is interrupted
		if(Thread.currentThread().isInterrupted()){
			Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
			return;
		}
			
			try{
				
				//try to connect with mailbox
				Properties props = new Properties();
				props.putAll(_mailAccount.getAccountProperties());
				
				//set connection timeout to 5 secods
				props.put("mail.imap.timeout", 5000);
				props.put("mail.imaps.timeout", 5000);
		
				Session session = Session.getInstance(props,
						_mailAccount.getPasswordAuthentication());
				
				store = session.getStore();
				
				//check if thread is interrupted
				if(Thread.currentThread().isInterrupted()){
					Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
					return;
				}
		
				store.connect(_mailAccount.getIncomingMailServerAddress(),
						_mailAccount.getAccountUsername(),
						_mailAccount.getAccountPassword());
		
				
				folder = (IMAPFolder)store.getDefaultFolder();
				folder = (IMAPFolder)store.getFolder("INBOX");
				folder.open(Folder.READ_WRITE);
				
				// message count adapter - new message coming -> check mailbox 
				_messageCountAdapter = new MessageCountAdapter() {
					
					public void messagesAdded(MessageCountEvent ev){
						
						Log.d(_logTag, "IMAPListenMailboxTask : new message is coming " + _mailAccount.getMailAddress());
						ReceivingRequestsHandler.checkMailBoxOnDemand(_mailAccount);
					}
					
				};
				folder.addMessageCountListener(_messageCountAdapter);
				
				
				//listen on new message arrival to INBOX folder
				boolean condition = true;
				while(condition && !Thread.currentThread().isInterrupted()){
					
					//Log.d(_logTag, "polling " + folder.getMessageCount() +" " + _mailAccount.getMailAddress());
					folder.getMessageCount();
					
					//check if thread is interrupted
					if(Thread.currentThread().isInterrupted()){
						
						folder.removeMessageCountListener(_messageCountAdapter);
						Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
						finish();
						return;
						
					} 
					
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {

						folder.removeMessageCountListener(_messageCountAdapter);
						Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
						finish();
						return;
					}
				}
				
				finish();
			
			} catch(MessagingException ex){
				
				Log.d(_logTag, "IMAPListenMailboxTask : messaging exception");	
				Log.d(_logTag, "IMAPListenMailBoxTask : "+ ex.getMessage() + " " + ex.toString());
				Log.d(_logTag, "IMAPListenMailBoxTask : " + _mailAccount.getMailAddress());
				
				//when catched messagin exception wait 1 second
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
					finish();
					return;
				}
				
				//check if thread is interrupted
				if(Thread.currentThread().isInterrupted()){
					folder.removeMessageCountListener(_messageCountAdapter);
					Log.d(_logTag, "Listening task interrupted " + _mailAccount.getMailAddress());
					return;
				}
				
				finish();
				run();
			} 
			
			Log.d(_logTag, "Listening task ended " + _mailAccount.getMailAddress());
	}
	
	/**
	 * @return - true if phone actually has internet connection, otherwise false
	 */
	private boolean isOnline() {
		
		 ConnectivityManager cm = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
		 
		 if( cm.getActiveNetworkInfo() == null)
			 return false;
		 else
			 return true;

	}
	
	private void finish() {
		
		try{
			if(folder != null)
				folder.close(false);
			if(store != null)
				store.close();
		} catch(MessagingException e){
			
			Log.d(_logTag,"IMAPListenMailboxTask : connection lost while finishing task");
		}
	}

	/**
	 * Folder object of INBOX folder in mailbox
	 */
	private IMAPFolder folder = null;
	
	/**
	 * IMAP store object
	 */
	private Store store = null;
	
	/**
	 * Message Count adapter
	 */
	private MessageCountAdapter _messageCountAdapter = null;
	
	/**
	 * MailAccount which is listening
	 */
	private MailAccount _mailAccount;
	
	/**
	 * Application context
	 */
	private Context _context;
	
	/**
	 * logTag for logging purposes
	 */
	private static String _logTag = "com.smartmail.receiving.imap";

}
